package cn.virens.config;

import java.nio.charset.Charset;
import java.util.List;

import javax.xml.transform.Source;

import org.apache.shiro.authz.HostUnauthorizedException;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authz.UnauthorizedException;
import org.beetl.core.misc.BeetlUtil;
import org.beetl.ext.spring.BeetlGroupUtilConfiguration;
import org.beetl.ext.spring.BeetlSpringViewResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.MediaType;
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.ResourceHttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.xml.SourceHttpMessageConverter;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import com.alibaba.fastjson.support.spring.FastJsonJsonView;

import cn.virens.components.spring.VirensExceptionResolver;
import cn.virens.components.spring.converter.CustomDateConverter;
import cn.virens.web.components.beetl.BeetlGroupUtilConfigurationBean;
import cn.virens.web.components.beetl.format.MessageFormat;
import cn.virens.web.components.beetl.format.StatusFormat;
import cn.virens.web.components.beetl.fun.PageUtil;
import cn.virens.web.components.beetl.tag.TestTag;

/**
 * Spring MVC 配置
 * 
 * @文件 :SpringMvcConfig.java
 * @作者 :cn.loioi
 * @创建时间 :2016年10月13日 下午1:12:09
 */
@EnableWebMvc
@Configuration
@ComponentScan("cn.loioi.web.controller")
@Import(value = { SpringWebSocketConfig.class })
public class ServletWebConfig extends WebMvcConfigurerAdapter {
	/**
	 * 文件上传配置
	 * 
	 * @return
	 */
	@Bean
	public CommonsMultipartResolver multipartResolver() {
		CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
		multipartResolver.setMaxUploadSize(10 * 1024 * 1024);
		return multipartResolver;
	}

	/**
	 * 内容协商器配置。将后缀为json的配置为json处理，后缀为jspx的为页面处理
	 */
	@Override
	public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
		configurer.defaultContentType(MediaType.APPLICATION_JSON_UTF8);

		configurer.mediaType("jspx", MediaType.TEXT_HTML);
		configurer.mediaType("json", MediaType.APPLICATION_JSON_UTF8);
	}

	/**
	 * 添加视图解析器
	 */
	@Override
	public void configureViewResolvers(ViewResolverRegistry registry) {
		BeetlSpringViewResolver beetlSpringViewResolver = new BeetlSpringViewResolver();
		beetlSpringViewResolver.setContentType("text/html;charset=UTF-8");
		beetlSpringViewResolver.setConfig(beetlConfiguration());
		beetlSpringViewResolver.setSuffix(".html");
		beetlSpringViewResolver.setOrder(2);

		registry.viewResolver(beetlSpringViewResolver);
		registry.enableContentNegotiation(new FastJsonJsonView());
	}

	/**
	 * 添加消息转换器
	 */
	@Override
	public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
		converters.add(new ByteArrayHttpMessageConverter());
		converters.add(new ResourceHttpMessageConverter());
		converters.add(new SourceHttpMessageConverter<Source>());
		converters.add(new StringHttpMessageConverter(Charset.forName("UTF-8")));
		converters.add(new FastJsonHttpMessageConverter());
	}

	/**
	 * 添加异常统一处理
	 */
	@Override
	public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
		VirensExceptionResolver exceptionResolver = new VirensExceptionResolver();

		exceptionResolver.addExceptionMessage(UnauthorizedException.class, "未授权");
		exceptionResolver.addExceptionMessage(UnauthenticatedException.class, "未登录");
		exceptionResolver.addExceptionMessage(DataIntegrityViolationException.class, "请检查约束");
		exceptionResolver.addExceptionMessage(MaxUploadSizeExceededException.class, "文件超出大小限制");

		exceptionResolver.addExceptionMappings(UnauthorizedException.class, "/error/401");
		exceptionResolver.addExceptionMappings(UnauthenticatedException.class, "/error/401");
		exceptionResolver.addExceptionMappings(HostUnauthorizedException.class, "/error/401");
		exceptionResolver.addExceptionMappings(NoHandlerFoundException.class, "/error/404");

		exceptionResolver.setDefaultErrorView("/error/500");
		exceptionResolver.setDefaultStatusCode(500);
		exceptionResolver.setExceptionAttribute("ex");
		exceptionResolver.init();

		exceptionResolvers.add(exceptionResolver);
	}

	/**
	 * 格式转换器
	 */
	@Override
	public void addFormatters(FormatterRegistry registry) {
		registry.addConverter(new CustomDateConverter());
	}

	/**
	 * 添加静态资源路径
	 */
	@Override
	public void addResourceHandlers(ResourceHandlerRegistry registry) {
		registry.addResourceHandler("/assets/**").addResourceLocations("/assets/");
		registry.addResourceHandler("/error/**").addResourceLocations("/error/");
		registry.addResourceHandler("/upload/**").addResourceLocations("/upload/");
		registry.addResourceHandler("/favicon.ico").addResourceLocations("/favicon.ico");
	}

	/**
	 * 跨域配置
	 */
	@Override
	public void addCorsMappings(CorsRegistry registry) {
		registry.addMapping("/api/**").allowedOrigins("*").allowedMethods("GET", "POST", "OPTIONS");
	}

	private BeetlGroupUtilConfiguration beetlConfiguration() {
		BeetlGroupUtilConfigurationBean bean = new BeetlGroupUtilConfigurationBean();

		bean.setRoot(BeetlUtil.getWebRoot() + "/WEB-INF/beetl/");
		bean.registerTagFactory("test", new TestTag());
		bean.registerFunction("PageUtil", new PageUtil());
		bean.registerFormat("status", new StatusFormat());
		bean.registerFormat("message", new MessageFormat());
		bean.afterPropertiesSet();

		return bean;
	}
}